﻿using System;
using System.Collections.Generic;
using System.Text;

namespace ConsoleApp_core
{
    public class GeneryT
    {
        public void Show()
        {
            Animal dog = new Dog();//正确

            Animal dog2 = new Dog();
            Animal fish = new Fish();

            //List<Animal> dogs = new List<Dog>();//报错 List<T>
            IEnumerable<Animal> dogs = new List<Dog>();//正确 IEnumerable<out T>  协变
            IEnumerable<Animal> fishs = new List<Fish>();//正确 IEnumerable<out T>  协变

        }
        public void Show2()
        {
            myOutInterface<Animal> dogs = new classOutT<Animal>();
            myOutInterface<Animal> dog2s = new classOutT<Dog>();
        }

        public void Show3()
        {
            myInInterface<Animal> dogs = new classIntT<Animal>();
            myInInterface<Dog> dog2s = new classIntT<Animal>();
            Dog dog = 1;
        }

    }

    class Animal
    {
    }

    class Dog : Animal
    {
        public static object operator +(Dog c1, Animal c2) { return new Dog(); }
        public static string operator -(Dog c1, Animal c2) { return ""; }
        public static implicit operator Dog(int c1) { return new Dog(); }
    }
    class Fish : Animal
    {

    }

    /// <summary>
    /// 协变例子
    /// 当声明为“out”时，代表它是用来返回的，只能作为结果返回，中途不能更改。
    /// </summary>
    /// <typeparam name="T"></typeparam>
    interface myOutInterface<out T>
    {
        T t
        {
            get;
            //set;//报错
        }
        //void SetT(T t);//报错
    }

    class classOutT<T> : myOutInterface<T>
    {
        public T t
        {
            get { return default(T); }
        }
    }

    /// <summary>
    /// 逆变例子
    /// 当声明为"in"时，代表它是用来输入的，只能作为参数输入，不能被返回。
    /// </summary>
    /// <typeparam name="T"></typeparam>
    interface myInInterface<in T>
    {
        T t
        {
            //get;//报错
            set;
        }
        void SetT(T t);
    }

    class classIntT<T> : myInInterface<T>
    {
        public T t { set => throw new NotImplementedException(); }

        public void SetT(T t)
        {
            throw new NotImplementedException();
        }
    }
}
